package com.see.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;

import org.slf4j.LoggerFactory;
import org.slf4j.Logger;

import com.see.domain.MessegeParser;
import com.see.exception.MessegeFeedException;
import com.see.exception.NoSuchSocketConnectionException;
import com.see.exception.UserExistException;
import com.see.exception.UserNotAuthenticatException;
import com.see.server.command.*;
import com.see.servise.SEEServise;

public class SocketConnection extends Thread {
	public Socket socket;
	public BufferedReader bufferedReader;
	public PrintWriter printWriter;
	public LinkedBlockingQueue<String> outMsgQueue; 
	private String userName;
	private Thread outputThread;
	private volatile boolean connectionClose = false;
	public SEEServise seeServise;
	private CommandHandler commandHandeler;
	
	private static Logger logger = LoggerFactory.getLogger(SocketConnection.class);
	
	public SocketConnection(Socket accept, SEEServise seeServise) throws IOException {
		this.commandHandeler = new CommandHandler(seeServise, this);
		this.socket = accept;
		this.seeServise = seeServise;
		this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		this.printWriter = new PrintWriter(socket.getOutputStream(), true);
		this.outMsgQueue = new LinkedBlockingQueue<>();
	}

	@Override
	public void run() {
		
		outputThread = new Thread(new Runnable() {
             @Override
             public void run() {
                     while(!Thread.interrupted()) {
                             sendMessege();
                     }
             }
		 });
		outputThread.start();
		 
		String message;
		Command command = new UnknownCommand();
		try {
			do {
				message = bufferedReader.readLine();
				if(message == null || message.equals(""))
					throw new IOException("Null or Empty msg from client");
					
				logger.info("server input msg" + message);
				try {
					command = commandHandeler.createCommand(new MessegeParser(message).parseMsg());
					placeMsgToOutputQueue(command.execute());
				} catch (MessegeFeedException  e) {
					placeMsgToOutputQueue(e.getMessage());
				} catch (UserNotAuthenticatException e) {
					placeMsgToOutputQueue(e.getMessage());
				} catch (UserExistException e) {
					placeMsgToOutputQueue(e.getMessage());
				}
			} while (!(command.getClass() == CloseCommand.class) && !Thread.interrupted());

		} catch (IOException e) {
			//do in finally block (closeConnection)			
		} finally {
			closeConnection();
		}

	}
	
	private void closeConnection(){
		if (!connectionClose) {
			try {
				try {
					ServerCore.getInstance().removeConnection(userName);
				} catch (NoSuchSocketConnectionException nosuchsocket) {
					logger.info("no such user:" + userName
								+ " in connection list");
				}

				logger.info("server: client disconnected");
				bufferedReader.close();
				printWriter.close();
				socket.close();
				outputThread.interrupt();
				Thread.currentThread().interrupt();
				connectionClose = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	public void placeMsgToOutputQueue(final String msg) {
		if (msg != null && !msg.equals(""))
			outMsgQueue.offer(msg);
	}
	
	public void sendMessege() {
		String msg = "";
		try {
			msg = outMsgQueue.take();
		} catch (InterruptedException e) {
			logger.error("sendMessege - InterruptedException");
			//closeConnection();
		}
		if(msg == null || msg.equals(""))return;
		logger.info("server output msg" + msg);
		printWriter.println(msg);
	}

	public synchronized String getUserName() {
		return userName;
	}

	public synchronized void setUserName(String userName) {
		this.userName = userName;
	}
	
	public synchronized boolean isAuthenticated(){
		return userName != null && userName != "";
	}
	
	
	
}
